跳到主要内容

protoc 的使用

官网这个 protoc 的使用方式介绍写的实在是模糊,这里重新整理一下

编写一个 Proto 文件

syntax = "proto3";
package tutorial;

import "google/protobuf/timestamp.proto";

option go_package = "github.com/protocolbuffers/protobuf/examples/go/tutorialpb";

版本的变化

官方在 Protocol Buffers v3.0.0 里介绍了,列举了 proto3 的改变:

  • 移除了原始值字段的出现逻辑。
  • 移除了 required 字段
  • 移除了缺省值
  • 移除了 unknown 字段 (3.5中又加上了)
  • 移除了扩展,使用 Any 代替
  • 修复了未知的枚举值的语义
  • 添加了 map 类型
  • 添加了一些标准类似,比如 time、动态数据的呈现
  • 可以使用 JSON 编码代替二进制 proto 编码

安装 protoc

安装编译器,参考 Protocol Buffer Compiler Installation

# 最简单的方式
sudo apt install -y protobuf-compiler

也可以选择手动安装 官方资源库

# 这里可以只下载对应的编译器的
wget https://github.com/protocolbuffers/protobuf/releases/download/v3.19.1/protoc-3.19.1-linux-x86_64.zip
unzip protoc-3.19.1-linux-x86_64.zip -d protobuf-3.19.1/

# 添加这个执行文件
vim ~/.bashrc
export PROTOBUF=/home/alsritter/tool/go/protobuf-3.19.1/
export PATH=$PATH:$GOROOT/bin:$GOPATH/bin:$PROTOBUF/bin

# 更新
source ~/.bashrc
# 检查是否安装完成
protoc --version

编译为 Go

用 protoc 来编译 .proto 文件为 go 语言,为了支持编译为 go,需要安装 protoc-gen-go 插件,C# 可以安装 protoc-gen-zsharp 插件。

go install google.golang.org/protobuf/cmd/protoc-gen-go@latest

这个 go_out 的使用参考官方文档 Go Generated Code

在命令行上可以使用 M${PROTO_FILE}=${GO_IMPORT_PATH} 指定 Go 导入路径

protoc --proto_path=src \
--go_opt=Mprotos/buzz.proto=example.com/project/protos/fizz \
--go_opt=Mprotos/bar.proto=example.com/project/protos/foo \
protos/buzz.proto protos/bar.proto

例如上面就是告诉编译器,遇到 protos/buzz.proto 就去 example.com/project/protos/fizz 目录里面找

编译命令

$ protoc --help
Usage: protoc [OPTION] PROTO_FILES

-IPATH, --proto_path=PATH 指定搜索路径
--plugin=EXECUTABLE:

....

--cpp_out=OUT_DIR Generate C++ header and source.
--csharp_out=OUT_DIR Generate C# source file.
--java_out=OUT_DIR Generate Java source file.
--js_out=OUT_DIR Generate JavaScript source.
--objc_out=OUT_DIR Generate Objective C header and source.
--php_out=OUT_DIR Generate PHP source file.
--python_out=OUT_DIR Generate Python source file.
--ruby_out=OUT_DIR Generate Ruby source file

@<filename> proto文件的具体位置


常用的 flag 介绍:

  • --proto_path 或者 -I 指定 protoc 的搜索 import 的 proto 的文件夹。
  • --go_out:参数之间用逗号隔开,最后用冒号来指定代码目录架构的生成位置
  • --go_out=plugins=grpc:参数来生成 gRPC 相关代码,如果不加 plugins=grpc,就只生成 message 数据

其中:

--go_out=plugins=grpc,paths=import:. 。注意一下 paths 参数,他有两个选项,import 和 source_relative 。默认为 import ,代表按照生成的 go 代码的包的全路径去创建目录层级,source_relative 代表按照 protobuf 源文件的目录层级去创建 go 代码的目录层级,如果目录已存在则不用创建

# 这里就是读取 protos 目录下的 proto 文件
protoc -I . --go_out=plugins=grpc:. --go_opt=paths=source_relative protos/*.proto

# 把 Proto 生成的文件生成到 hello_proto 目录下面,主要需要有这个文件才行
protoc -I ./protos --go_out=plugins=grpc:./hello_proto --go_opt=paths=source_relative protos/*.proto

其实很简单,看最后一个参数,例如 protos/*.proto 的前面是空格,就是表示目标 proto 文件的位置,前面的 flag 则是指定生成的位置

实例

# 进入到 proto 目录中,输入
$ protoc *.proto --go_out=plugins=grpc:. --go_opt=paths=source_relative

# 或者在项目的根目录输入
# --go_opt=paths=source_relative 表示要用相对路径产生
$ protoc -I <src_proto_folder> --go_out=plugins=grpc:<dist_directory> --go_opt=paths=source_relative <src_proto_file_path>

$ protoc -I proto/jubox --go_out=plugins=grpc:proto/jubox --go_opt=paths=source_relative proto/jubox/jubox.proto

# 產生編譯檔(產生一般的 .pb.go 檔,但沒有使用 gRPC plugin
$ protoc -I=$SRC_DIR --go_out=$DST_DIR $SRC_DIR/addressbook.proto # 預設根據 go_package 路徑

# 產生 proto 檔,預設將根據 proto 中的 go_package 路徑
$ protoc -I=$SRC_DIR --go_out=$DST_DIR $SRC_DIR/addressbook.proto


# 另一種寫法會 build 出兩隻檔案,一支是 proto buffer(foobar.pb.go),一支是 gRPC 用的檔案(foobar_grpc.pb.go)
$ protoc --go_out=. --go_opt=paths=source_relative --go-grpc_out=. --go-grpc_opt=paths=source_relative {proto_filename}.proto

References